package section

import (
	"context"
	"strconv"
	"strings"

	"mall/common/globalkey"
	"mall/common/utils/pointy"
	"mall/service/backend/api/internal/logic/system/util"
	"mall/service/backend/api/internal/logic/utils"
	"mall/service/backend/api/internal/logic/utils/parse"
	"mall/service/backend/api/internal/svc"
	"mall/service/backend/api/internal/types"
	"mall/service/backend/common/enum/errorcode"
	"mall/service/backend/common/errorx"
	"mall/service/backend/common/i18n"
	"mall/service/backend/rpc/backendclient"
	"mall/service/product/rpc/productclient"

	"github.com/zeromicro/go-zero/core/logx"
)

type GetSectionProductListLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGetSectionProductListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetSectionProductListLogic {
	return &GetSectionProductListLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GetSectionProductListLogic) GetSectionProductList(req *types.SectionProductListReq) (*types.SectionProductListResp, error) {
	if req.SectionId == nil || *req.SectionId == 0 {
		return nil, errorx.NewCodeError(errorcode.InvalidArgument,
			l.svcCtx.Trans.Trans(l.ctx, "common.validationError"))
	}

	page, pageSize := parse.ParsePageInfo(
		req.Current,
		req.PageSize,
		l.svcCtx.Config.Query.DefaultAmount,
		l.svcCtx.Config.Query.MaxAmount,
	)

	orderBys := util.ParseSorter(req.Sorter)
	filterBys := util.ParseFilter(req.Filter)

	res, err := l.svcCtx.BackendRpc.BackendGetSectionProductList(l.ctx, &backendclient.SectionProductListReq{
		Page:      page,
		PageSize:  pageSize,
		SectionId: req.SectionId,
		// BrandId:    req.BrandId,
		// CategoryId: req.CategoryId,
		// ProductId:  req.ProductId,
		OrderBy:  orderBys,
		FilterBy: filterBys,
	})
	if err != nil {
		return nil, err
	}

	// logx.Infof("GetSectionProductList : %+v ", res)
	// GetSectionProductList : Total:7  List:{Id:25  SectionId:11  BrandId:44089  CategoryId:0  ProductId:0  Sort:0}  List:{Id:2  SectionId:11  BrandId:0  CategoryId:0  ProductId:9  Sort:2}  List:{Id:3  SectionId:11  BrandId:0  CategoryId:0  ProductId:10  Sort:3}  List:{Id:4  SectionId:11  BrandId:0  CategoryId:0  ProductId:11  Sort:4}  List:{Id:5  SectionId:11  BrandId:0  CategoryId:0  ProductId:12  Sort:5}  List:{Id:21  SectionId:11  BrandId:0  CategoryId:0  ProductId:15  Sort:13}  List:{Id:22  SectionId:11  BrandId:0  CategoryId:0  ProductId:56  Sort:15}

	resp := &types.SectionProductListResp{
		BaseDataInfo: types.BaseDataInfo{
			Success: true,
			Msg:     l.svcCtx.Trans.Trans(l.ctx, i18n.Success),
		},
		Data: types.SectionProductListInfo{
			BaseListInfo: types.BaseListInfo{
				Current:  page,
				PageSize: pageSize,
			},
		},
	}

	var total uint64
	if len(res.List) > 0 {
		var ids []string
		var bids []string
		var tids []string
		idSortMap := make(map[uint64]uint32)
		bidSortMap := make(map[uint64]uint32)
		tidSortMap := make(map[uint64]uint32)
		for _, v := range res.List {
			if v.BrandId != nil && *v.BrandId > 0 {
				bids = append(bids, strconv.FormatUint(*v.BrandId, 10))
				if v.Sort != nil {
					bidSortMap[*v.BrandId] = *v.Sort
				}
			}
			if v.ProductId != nil && *v.ProductId > 0 {
				ids = append(ids, strconv.FormatUint(*v.ProductId, 10))
				if v.Sort != nil {
					idSortMap[*v.ProductId] = *v.Sort
				}
			}
			if v.CategoryId != nil && *v.CategoryId > 0 {
				tids = append(tids, strconv.FormatUint(*v.CategoryId, 10))
				if v.Sort != nil {
					tidSortMap[*v.CategoryId] = *v.Sort
				}
			}
		}

		// logx.Infof("GetSectionProductList idSortMap : %+v ", idSortMap)
		// logx.Infof("GetSectionProductList bidSortMap : %+v ", bidSortMap)
		// logx.Infof("GetSectionProductList tidSortMap : %+v ", tidSortMap)

		productMap := make(map[uint64]struct{})
		if len(bids) > 0 {
			data, err := l.svcCtx.ProductRpc.BackendGetProductList(l.ctx, &productclient.ProductListReq{
				BrandIds:  pointy.GetPointer(strings.Join(bids, ",")),
				WithEntry: pointy.GetPointer(uint32(1)),
			})
			if err != nil {
				return nil, err
			}

			if len(data.List) > 0 {
				brandMap := make(map[uint64]struct{})
				for _, v := range data.List {
					if v.Id != nil && *v.Id > 0 {
						if _, ok := productMap[*v.Id]; ok {
							continue
						}

						productMap[*v.Id] = struct{}{}
					}

					var media []*types.MediaInfo
					if len(v.Media) > 0 {
						for _, m := range v.Media {
							var url string
							if m.Url != nil && len(*m.Url) > 0 {
								url = *m.Url
							}
							if len(url) == 0 && m.Uri != nil && len(*m.Uri) > 0 {
								url = *m.Uri
							}
							filename, mimeType, metaData := utils.ParseMetaData(m.MetaData)
							media = append(media, &types.MediaInfo{
								Uid:       m.Uid,
								Id:        m.Id,
								Thumbnail: m.Thumbnail,
								Order:     m.Order,
								Url:       pointy.GetPointer(url),
								Name:      pointy.GetPointer(filename),
								MimeType:  pointy.GetPointer(mimeType),
								AltText:   m.AltText,
								MetaData:  pointy.GetPointer(metaData),
							})
						}
					}
					var brandId *uint64
					var brandName *string
					var brandSlug *string
					var sort *uint32
					if len(v.Relations) > 0 {
						for _, entry := range v.Relations {
							if entry.Id != nil && *entry.Id > 0 && entry.Key != nil && *entry.Key == globalkey.ProductRelationNameBrand {
								if _, ok := brandMap[*entry.Id]; !ok {
									if sorter, ok := bidSortMap[*entry.Id]; ok {
										brandId = entry.Id
										brandName = entry.Name
										brandSlug = entry.Slug
										sort = pointy.GetPointer(sorter)
										resp.Data.BrandList = append(resp.Data.BrandList, &types.SectionBrandInfo{
											Id:    brandId,
											Title: brandName,
											Slug:  brandSlug,
											Sort:  sort,
										})
										brandMap[*brandId] = struct{}{}
									}
								}
							}
						}
					}

					resp.Data.List = append(resp.Data.List, &types.SectionProductInfo{
						Id:        v.Id,
						Title:     v.Title,
						Slug:      v.Slug,
						BrandId:   brandId,
						BrandName: brandName,
						BrandSlug: brandSlug,
						Sort:      sort,
						Status:    v.Status,
						Media:     media,
						CanRemove: pointy.GetPointer(false),
					})
				}
			}
		}
		if len(tids) > 0 {
			data, err := l.svcCtx.ProductRpc.BackendGetProductList(l.ctx, &productclient.ProductListReq{
				CategoryIds: pointy.GetPointer(strings.Join(tids, ",")),
				WithTag:     pointy.GetPointer(uint32(1)),
			})
			if err != nil {
				return nil, err
			}

			if len(data.List) > 0 {
				tagMap := make(map[uint64]struct{})
				for _, v := range data.List {
					if v.Id != nil && *v.Id > 0 {
						if _, ok := productMap[*v.Id]; ok {
							continue
						}

						productMap[*v.Id] = struct{}{}
					}

					var media []*types.MediaInfo
					if len(v.Media) > 0 {
						for _, m := range v.Media {
							var url string
							if m.Url != nil && len(*m.Url) > 0 {
								url = *m.Url
							}
							if len(url) == 0 && m.Uri != nil && len(*m.Uri) > 0 {
								url = *m.Uri
							}
							filename, mimeType, metaData := utils.ParseMetaData(m.MetaData)
							media = append(media, &types.MediaInfo{
								Uid:       m.Uid,
								Id:        m.Id,
								Thumbnail: m.Thumbnail,
								Order:     m.Order,
								Url:       pointy.GetPointer(url),
								Name:      pointy.GetPointer(filename),
								MimeType:  pointy.GetPointer(mimeType),
								AltText:   m.AltText,
								MetaData:  pointy.GetPointer(metaData),
							})
						}
					}
					var tagId *uint64
					var tagName *string
					var tagSlug *string
					var sort *uint32
					if len(v.Tags) > 0 {
						for _, tag := range v.Tags {
							if tag.Id != nil && *tag.Id > 0 {
								if _, ok := tagMap[*tag.Id]; !ok {
									if sorter, ok := tidSortMap[*tag.Id]; ok {
										tagId = tag.Id
										tagName = tag.Name
										tagSlug = tag.Slug
										sort = pointy.GetPointer(sorter)
										resp.Data.TagList = append(resp.Data.TagList, &types.ProductTermInfo{
											BaseIDInfo: types.BaseIDInfo{
												Id: tagId,
											},
											Name: tagName,
											Slug: tagSlug,
											Sort: sort,
										})
										tagMap[*tagId] = struct{}{}
									}
								}
							}
						}
					}

					resp.Data.List = append(resp.Data.List, &types.SectionProductInfo{
						Id:        v.Id,
						Title:     v.Title,
						Slug:      v.Slug,
						TagId:     tagId,
						TagName:   tagName,
						TagSlug:   tagSlug,
						Sort:      sort,
						Status:    v.Status,
						Media:     media,
						CanRemove: pointy.GetPointer(false),
					})
				}
			}
		}
		if len(ids) > 0 {
			data, err := l.svcCtx.ProductRpc.BackendGetProductList(l.ctx, &productclient.ProductListReq{
				Ids:       pointy.GetPointer(strings.Join(ids, ",")),
				WithEntry: pointy.GetPointer(uint32(1)),
			})
			if err != nil {
				return nil, err
			}

			if len(data.List) > 0 {
				for _, v := range data.List {
					// logx.Infof("GetSectionProductList productMap : %+v ", v)
					var sort *uint32
					if v.Id != nil && *v.Id > 0 {
						if _, ok := productMap[*v.Id]; ok {
							continue
						}

						productMap[*v.Id] = struct{}{}
						if sorter, ok := idSortMap[*v.Id]; ok {
							sort = pointy.GetPointer(sorter)
						}
					}

					var media []*types.MediaInfo
					if len(v.Media) > 0 {
						for _, m := range v.Media {
							var url string
							if m.Url != nil && len(*m.Url) > 0 {
								url = *m.Url
							}
							if len(url) == 0 && m.Uri != nil && len(*m.Uri) > 0 {
								url = *m.Uri
							}
							filename, mimeType, metaData := utils.ParseMetaData(m.MetaData)
							media = append(media, &types.MediaInfo{
								Uid:       m.Uid,
								Id:        m.Id,
								Thumbnail: m.Thumbnail,
								Order:     m.Order,
								Url:       pointy.GetPointer(url),
								Name:      pointy.GetPointer(filename),
								MimeType:  pointy.GetPointer(mimeType),
								AltText:   m.AltText,
								MetaData:  pointy.GetPointer(metaData),
							})
						}
					}
					var brandId *uint64
					var brandName *string
					var brandSlug *string
					if len(v.Relations) > 0 {
						for _, entry := range v.Relations {
							if entry.Key != nil && *entry.Key == globalkey.ProductRelationNameBrand {
								brandId = entry.Id
								brandName = entry.Name
								brandSlug = entry.Slug
							}
						}
					}

					resp.Data.List = append(resp.Data.List, &types.SectionProductInfo{
						Id:        v.Id,
						Title:     v.Title,
						Slug:      v.Slug,
						BrandId:   brandId,
						BrandName: brandName,
						BrandSlug: brandSlug,
						Sort:      sort,
						Status:    v.Status,
						Media:     media,
						CanRemove: pointy.GetPointer(true),
					})
				}
			}
		}
		resp.Data.Total = total
	}

	return resp, nil
}
